#ifndef __BLOCK_HPP__
#define __BLOCK_HPP__

#include <iomanip>
#include <iostream>
#include <string>
#include <string.h>

#include "GenericException.hpp"

/**
 * represents a block of data
 */
class Block {
	private:
		unsigned char *data;
		unsigned int length;
		unsigned int customBlockSize;
	public:
		/**
		 * initializes Block with no content
		 */
		Block();

		/**
		 * copies data from other Block
		 * @param other other block that data is copied from
		 */
		Block(const Block &other);

		/**
		 * initializes block with given length
		 * @param length length of block in bytes
		 */
		Block(unsigned int length);

		/**
		 * initializes block with given pattern
		 * @param length length of new block in bytes
		 * @param pattern byte that is used to fill buffer with
		 */
		Block(unsigned int length, char pattern);

		/**
		 * initializes block with given data
		 * @param initData data block that buffer is initialized with
		 * @param length length of buffer in bytes (must be equal to length of initData)
		 */
		Block(const unsigned char* initData, unsigned int length);

		/**
		 * initializes Block with given string
		 * @param initData string block should be initialized with (buffer length will be equal to string length)
		 */
		Block(const std::string &initData);

		virtual ~Block();

		/**
		 * sets Block to given hexadecimal string
		 * @param hexString hexadecimal string, where each character represents a number between 0 and 15 (0 and f/F)
		 *                  sample string "abcdef01234567890ABCDEF"
		 */
		void setToHex(const std::string &hexString);

		/**
		 * changes length of buffer
		 * @param length new length of buffer in bytes
		 */
		void changeSize(unsigned int length);

		/**
		 * rewrites buffer with 0, current length is kept
		 */
		void clear() const;

		/**
		 * frees internal structures
		 */
		void free();

		/**
		 * truncates buffer to new length
		 * @param newLength length in bytes that buffer needs to be truncated to
		 */
		void truncate(unsigned int newLength);

		/**
		 * @returns buffer as array (modifiable)
		 */
		unsigned char* get() const;

		/**
		 * @returns buffer as array (non-modifiable)
		 */
		const unsigned char *getRO() const;

		/**
		 * @returns current buffer length in bytes
		 */
		unsigned int getLength() const;


		/**
		 * XORs this block with another block
		 * Be aware that the XOR-operation on blocks is *left* aligned. This means, e.g.
		 * Block("foo") ^ Block("foobar") = Block("\0\0\0bar")
		 * 
		 * @param other block
		 */
		Block operator^(const Block &other) const;

		/**
		 * shifts this block left by given numer of bits
		 * @param bits
		 */
		void operator<<=(unsigned int bits);

		/**
		 * shifts this block right by given numer of bits
		 * @param bits
		 */
		void operator>>=(unsigned int bits);

		/**
		 * dumps this block to given stream
		 * @param outStrm stream to be used for dump, e.g. std::cout
		 */
		void dump(std::ostream &outStrm) const;

		/**
		 * dumps this block to given stream (short message)
		 * @param outStrm stream to be used for dump, e.g. std::cout
		 * @param caption caption for dump
		 */
		void shortDump(std::ostream &outStrm, const std::string &caption) const;

		void operator=(const Block &other);
		bool operator==(const Block &other) const;
		bool operator!=(const Block &other) const;
		void operator^=(const Block &other);
};
#endif

